/*
 * Copyright (c) 2020 libinal's testing project.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * imitations under the License.
 */

package com.platform.comm.util;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * Description: RSA Util
 *
 * @author Coder created on 2019/11/22
 */
public final class RsaUtils {
    /**
     * 缺省的2048位密钥对,可处理245个字节(81个汉字)的数据
     */
    private static String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxbgcDhNDfTrSMBRCT2z8RtsdMGARW0RTbyhlxLvJq0eYAzFuNe8y5YkErZ10vq1502LWyENzlww1nWJC5N8UKoh5tcFzC4Ky+65dN6a1qysZHmzA1YZilG/VFfjtLR91rwmaEFoFPfK+EMys0wHOr+J6+mKv+A8jKjbzCNGTcBLRLK9k+cehBUr0DyN3ANQ+Ml0VhgUyGMntGOgCh54i1El82VbCVxA5Si4KiofjX+bgYG/RaBZcmWG8qym3rMgKfqFKzK9DIQ3n/Q99iCVIjrMId9K+/+iOjRNJovKuiXztfJA1nzeuiblR2gW/ZJYxxA6URbprfrpziIvlsQN9PwIDAQAB";

    private static String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDFuBwOE0N9OtIwFEJPbPxG2x0wYBFbRFNvKGXEu8mrR5gDMW417zLliQStnXS+rXnTYtbIQ3OXDDWdYkLk3xQqiHm1wXMLgrL7rl03prWrKxkebMDVhmKUb9UV+O0tH3WvCZoQWgU98r4QzKzTAc6v4nr6Yq/4DyMqNvMI0ZNwEtEsr2T5x6EFSvQPI3cA1D4yXRWGBTIYye0Y6AKHniLUSXzZVsJXEDlKLgqKh+Nf5uBgb9FoFlyZYbyrKbesyAp+oUrMr0MhDef9D32IJUiOswh30r7/6I6NE0mi8q6JfO18kDWfN66JuVHaBb9kljHEDpRFumt+unOIi+WxA30/AgMBAAECggEAXnsFBQDVjkEOcaUsrrGgt+c6woQVpyw2RnbicqldzDgw/s2fIazFAISCNMh6IifZgFbJ1fbNhI90C1oKJz4mb9C5gE4JwKVbDAOdTdufEkVNAonrd914u//YrmA+TgKrhNIsycWKnbiidHqp10cU0l2CcKW5+uqY3jJV3o/vSW0NKqiNzN1/VnaePcuMzwedVEmOqVdZEck+JKpe90FJt65IFPPaovcMdZTzpqc7Sqk8rrvClfekHSpApmpVcWe4Xa9TKY3Cj2xQAs1E+vB3L89hvKQsj+r2QxE/apSOz9IywHXC9PtEJN95pzeokjSJn8WMtVaFn6STafCx0tbuSQKBgQDtouue0Vf4gYqKYxXY/mn7fQ1vp0SSm1W82RbN1UxSpNJgwdYfNBOwA33WfCviBDMHWF8xltJxlrieuocYMyJwoCwkR24DYRarUkJ4Sqg7HnPbxS/XJXH7ppCv9McWsXzrxYUGvhCdLNKFJ7EcM6q5VLh5bZ/IzIzeAexDMuONlQKBgQDU/4Uz8A3sLurTCaT6oTFOW5CDRs4j5iqT8ifPKhszJVZMoUJeEm+MMHNLHphIyaL/VEOGLSUAYUsi9CJRS/Eq8jv0dgbGrR3RI6ROIVkqX7SF20nqrD2MF0Iwjtqlc36qXYmEJkhFgbj2BWWmeF0jTawlPB3p72lSmvw8syNigwKBgFVoEorX7mgQFry58+YzOd/7B9MzKMAQN/ZRh5KesHmbZ0kDIXPBgbnm51ko85SdscFYD46BCE1uwBe8LkWSSzRzPKolSfLI+B7Gx8D4BBKLVVSNQC5w9NBfAu1aahtL2vvZ13+e29XBgD//DfZ200scmdh6f8zpR0+bHVDhf0spAoGBAKk3fzmuA0GaXJDg3qMHIMbh08OXovm+SCFVhu78wrM1fIRQsQtPljNH4rDRU6awGsDCzwpwHy9YHHtefU0dCjJWU+95PRTmQAQBTu2LbO1PL3oQp3667AK6D6nINEixovXybegBCfW+g5Vg4EsK4OPFN3g1dIZ/36ry2mXW48vFAoGAW69F3AnhU/5H7f3z7NFzjX47l7oMc9xr+SI9zRvDK3QETwnZgx6o6vs52qvurC9FhhSFXXeqvi+XoTqU8D3d9NSJgE83r4LTRQzWj4C9t8nCazXzlNYzaB3ND93N6lQRtqrPXsyVm2p2x8ldOqGXogeDqSySBmRrA9tkTrgoQaU=";

    /**
     * 字符集
     */
    private static String CHARSET = "utf-8";

    /**
     * 签名算法
     */
    private static final String SIGNATURE_INSTANCE = "SHA1WithRSA";

    /**
     * 生成密钥对
     *
     * @param keyLength 秘钥长度
     * @return 秘钥对
     * @throws Exception 异常
     */
    public static KeyPair getKeyPair(int keyLength) throws Exception {
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(keyLength);
        return keyGen.generateKeyPair();
    }

    /**
     * 公钥字符串转PublicKey实例
     *
     * @param publicKey 公钥
     * @return 公钥
     * @throws Exception 异常
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 私钥字符串转PrivateKey实例
     *
     * @param privateKey 私钥
     * @return 私钥
     * @throws Exception 异常
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 公钥加密
     *
     * @param content   原文
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 异常
     */
    public static byte[] encryptByPublicKey(byte[] content, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }

    public static byte[] encryptByPublicKey(byte[] content) throws Exception {
        return encryptByPublicKey(content, getPublicKey(PUBLIC_KEY));
    }

    /**
     * 公钥加密
     *
     * @param content   原文
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 异常
     */
    public static String encryptByPublicKey(String content, String publicKey) throws Exception {
        return new String(Base64.getEncoder().encode(encryptByPublicKey(content.getBytes(CHARSET), getPublicKey(publicKey))));

    }

    /**
     * 公钥加密(使用内置秘钥)
     *
     * @param content 原文
     * @return 密文
     * @throws Exception 异常
     */
    public static String encryptByPublicKey(String content) throws Exception {
        return new String(Base64.getEncoder().encode(encryptByPublicKey(content.getBytes(CHARSET))));
    }

    /**
     * 私钥解密
     *
     * @param content    密文
     * @param privateKey 私钥
     * @return 原文
     * @throws Exception 异常
     */
    public static byte[] decryptByPrivateKey(byte[] content, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }

    /**
     * 私钥解密(使用内置秘钥)
     *
     * @param content 密文
     * @return 原文
     * @throws Exception 异常
     */
    public static byte[] decryptByPrivateKey(byte[] content) throws Exception {
        return decryptByPrivateKey(content, getPrivateKey(PRIVATE_KEY));
    }

    /**
     * 私钥解密
     *
     * @param content    密文
     * @param privateKey 私钥
     * @return 原文
     * @throws Exception 异常
     */
    public static String decryptByPrivateKey(String content, String privateKey) throws Exception {
        return new String(decryptByPrivateKey(Base64.getDecoder().decode(content), getPrivateKey(privateKey)), CHARSET);

    }

    /**
     * 私钥解密(使用内置秘钥)
     *
     * @param content 密文
     * @return 原文
     * @throws Exception 异常
     */
    public static String decryptByPrivateKey(String content) throws Exception {
        return new String(decryptByPrivateKey(Base64.getDecoder().decode(content)), CHARSET);
    }

    /**
     * 私钥加密
     *
     * @param content    原文
     * @param privateKey 私钥
     * @return 密文
     * @throws Exception 异常
     */
    public static byte[] encryptByPrivateKey(byte[] content, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(content);
    }

    /**
     * 私钥加密(使用内置秘钥)
     *
     * @param content 原文
     * @return 密文
     * @throws Exception 异常
     */
    public static byte[] encryptByPrivateKey(byte[] content) throws Exception {
        return encryptByPrivateKey(content, getPrivateKey(PRIVATE_KEY));
    }

    /**
     * 私钥加密
     *
     * @param content    原文
     * @param privateKey 私钥
     * @return 密文
     * @throws Exception 异常
     */
    public static String encryptByPrivateKey(String content, String privateKey) throws Exception {
        return new String(encryptByPrivateKey(content.getBytes(CHARSET), getPrivateKey(privateKey)), CHARSET);
    }

    /**
     * 私钥加密(使用内置秘钥)
     *
     * @param content 原文
     * @return 密文
     * @throws Exception 异常
     */
    public static String encryptByPrivateKey(String content) throws Exception {
        return new String(encryptByPrivateKey(content.getBytes(CHARSET)), CHARSET);
    }

    /**
     * 公钥解密
     *
     * @param content   密文
     * @param publicKey 公钥
     * @return 原文
     * @throws Exception 异常
     */
    public static byte[] decryptByPublicKey(byte[] content, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(content);
    }

    /**
     * 公钥解密(使用内置秘钥)
     *
     * @param content 密文
     * @return 原文
     * @throws Exception 异常
     */
    public static byte[] decryptByPublicKey(byte[] content) throws Exception {
        return decryptByPublicKey(content, getPublicKey(PUBLIC_KEY));
    }

    /**
     * 公钥解密
     *
     * @param content   密文
     * @param publicKey 公钥
     * @return 原文
     * @throws Exception 异常
     */
    public static String decryptByPublicKey(String content, String publicKey) throws Exception {
        return new String(decryptByPublicKey(Base64.getDecoder().decode(content), getPublicKey(publicKey)), CHARSET);

    }

    /**
     * 公钥解密(使用内置秘钥)
     *
     * @param content 密文
     * @return 原文
     * @throws Exception 异常
     */
    public static String decryptByPublicKey(String content) throws Exception {
        return new String(decryptByPublicKey(Base64.getDecoder().decode(content)), CHARSET);
    }

    /**
     * 使用私钥签名
     *
     * @param content    原文
     * @param privateKey 私钥
     * @return 签名
     * @throws Exception 异常
     */
    public static byte[] sign(byte[] content, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initSign(privateKey);
        signature.update(content);
        return signature.sign();
    }

    /**
     * 使用私钥签名(使用内置秘钥)
     *
     * @param content 原文
     * @return 签名
     * @throws Exception 异常
     */
    public static byte[] sign(byte[] content) throws Exception {
        return sign(content, getPrivateKey(PRIVATE_KEY));
    }

    /**
     * 使用私钥签名
     *
     * @param content    原文
     * @param privateKey 私钥
     * @return 签名
     * @throws Exception 异常
     */
    public static String sign(String content, String privateKey) throws Exception {
        return new String(Base64.getEncoder().encode(sign(content.getBytes(CHARSET), getPrivateKey(privateKey))), CHARSET);
    }

    /**
     * 使用私钥签名(使用内置秘钥)
     *
     * @param content 原文
     * @return 签名
     * @throws Exception 异常
     */
    public static String sign(String content) throws Exception {
        return new String(Base64.getEncoder().encode(sign(content.getBytes(CHARSET))), CHARSET);
    }

    /**
     * 验签
     *
     * @param content   原文
     * @param sign      签名
     * @param publicKey 公钥
     * @return Boolean
     * @throws Exception 异常
     */
    public static boolean verify(byte[] content, byte[] sign, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initVerify(publicKey);
        signature.update(content);
        return signature.verify(sign);
    }

    /**
     * 验签
     *
     * @param content 原文
     * @param sign    签名
     * @return Boolean
     * @throws Exception 异常
     */
    public static boolean verify(byte[] content, byte[] sign) throws Exception {
        return verify(content, sign, getPublicKey(PUBLIC_KEY));
    }

    /**
     * 验签
     *
     * @param content   原文
     * @param sign      签名
     * @param publicKey 公钥
     * @return Boolean
     * @throws Exception 异常
     */
    public static boolean verify(String content, String sign, String publicKey) throws Exception {
        return verify(content.getBytes(CHARSET), Base64.getDecoder().decode(sign), getPublicKey(publicKey));
    }

    /**
     * 验签
     *
     * @param content 原文
     * @param sign    签名
     * @return Boolean
     * @throws Exception 异常
     */
    public static boolean verify(String content, String sign) throws Exception {
        return verify(content.getBytes(CHARSET), Base64.getDecoder().decode(sign), getPublicKey(PUBLIC_KEY));
    }

    private RsaUtils() {
    }
}
